

import 'dart:typed_data';

import 'package:flutter/services.dart';
import 'package:tencent_rtc/bridge/trtc_method_channel.dart';
import 'package:tencent_rtc/trtc_cloud.dart';
import 'package:tencent_rtc/trtc_cloud_def.dart';
import 'package:tencent_rtc/trtc_cloud_listener.dart';

import 'package:tencent_rtc/tx_audio_effect_manager.dart';
import 'package:tencent_rtc/tx_device_manager.dart';

import '../bridge/trtc_channel_listener.dart';

abstract class ListenerParse<T> {
  final Set<T> _listeners = {};

  void addListener(T listener) {
    _listeners.add(listener);
  }

  void removeListener(T listener) {
    _listeners.remove(listener);
  }

  void clearListeners() {
    _listeners.clear();
  }

  void handleListener(String type, Map<String, dynamic> param);
}

class TRTCCloudListenerParse extends ListenerParse<TRTCCloudListener> {

  TRTCCloudListenerParse() {
    TRTCMethodChannel().setListener(getChannelListener());
  }

  TRTCChannelListener getChannelListener() {
    return TRTCChannelListener(
        handleNativeOnSnapshotComplete: (arguments) {
          var path = arguments["path"] ?? "";
          var errCode = arguments["errCode"] ?? -1;
          var errMsg = arguments["errMsg"] ?? "parameter parsing error";
          var userId = arguments["userId"] ?? "";

          for (TRTCCloudListener item in _listeners) {
            item.onSnapshotComplete?.call(userId, path, errCode, errMsg);
          }
        }
    );
  }

  @override
  handleListener(String type, Map<String, dynamic> param) {
    switch (type) {
      case "onError":
        _handleOnError(param);
        break;
      case "onWarning":
        _handleOnWarning(param);
        break;
      case "onEnterRoom":
        _handleOnEnterRoom(param);
        break;
      case "onExitRoom":
        _handleOnExitRoom(param);
        break;
      case "onSwitchRole":
        _handleOnSwitchRole(param);
        break;
      case "onSwitchRoom":
        _handleOnSwitchRoom(param);
        break;
      case "onConnectOtherRoom":
        _handleOnConnectOtherRoom(param);
        break;
      case "onDisconnectOtherRoom":
        _handleOnDisconnectOtherRoom(param);
        break;
      case "onRemoteUserEnterRoom":
        _handleOnRemoteUserEnterRoom(param);
        break;
      case "onRemoteUserLeaveRoom":
        _handleOnRemoteUserLeaveRoom(param);
        break;
      case "onUserVideoAvailable":
        _handleOnUserVideoAvailable(param);
        break;
      case "onUserSubStreamAvailable":
        _handleOnUserSubStreamAvailable(param);
        break;
      case "onUserAudioAvailable":
        _handleOnUserAudioAvailable(param);
        break;
      case "onFirstVideoFrame":
        _handleOnFirstVideoFrame(param);
        break;
      case "onFirstAudioFrame":
        _handleOnFirstAudioFrame(param);
        break;
      case "onSendFirstLocalVideoFrame":
        _handleOnSendFirstLocalVideoFrame(param);
        break;
      case "onSendFirstLocalAudioFrame":
        _handleOnSendFirstLocalAudioFrame(param);
        break;
      case "onRemoteVideoStatusUpdated":
        _handleOnRemoteVideoStatusUpdated(param);
        break;
      case "onRemoteAudioStatusUpdated":
        _handleOnRemoteAudioStatusUpdated(param);
        break;
      case "onUserVideoSizeChanged":
        _handleOnUserVideoSizeChanged(param);
        break;
      case "onNetworkQuality":
        _handleOnNetworkQuality(param);
        break;
      case "onStatistics":
        _handleOnStatistics(param);
        break;
      case "onSpeedTestResult":
        _handleOnSpeedTestResult(param);
        break;
      case "onConnectionLost":
        _handleOnConnectionLost(param);
        break;
      case "onTryToReconnect":
        _handleOnTryToReconnect(param);
        break;
      case "onConnectionRecovery":
        _handleOnConnectionRecovery(param);
        break;
      case "onCameraDidReady":
        _handleOnCameraDidReady(param);
        break;
      case "onMicDidReady":
        _handleOnMicDidReady(param);
        break;
      case "onUserVoiceVolume":
        _handleOnUserVoiceVolume(param);
        break;
      case "onAudioDeviceCaptureVolumeChanged":
        _handleOnAudioDeviceCaptureVolumeChanged(param);
        break;
      case "onAudioDevicePlayoutVolumeChanged":
        _handleOnAudioDevicePlayoutVolumeChanged(param);
        break;
      case "onSystemAudioLoopbackError":
        _handleOnSystemAudioLoopbackError(param);
        break;
      case "onTestMicVolume":
        _handleOnTestMicVolume(param);
        break;
      case "onTestSpeakerVolume":
        _handleOnTestSpeakerVolume(param);
        break;
      case "onRecvCustomCmdMsg":
        _handleOnRecvCustomCmdMsg(param);
        break;
      case "onMissCustomCmdMsg":
        _handleOnMissCustomCmdMsg(param);
        break;
      case "onRecvSEIMsg":
        _handleOnRecvSEIMsg(param);
        break;
      case "onStartPublishMediaStream":
        _handleOnStartPublishMediaStream(param);
        break;
      case "onUpdatePublishMediaStream":
        _handleOnUpdatePublishMediaStream(param);
        break;
      case "onStopPublishMediaStream":
        _handleOnStopPublishMediaStream(param);
        break;
      case "onCdnStreamStateChanged":
        _handleOnCdnStreamStateChanged(param);
        break;
      case "onScreenCaptureStarted":
        _handleOnScreenCaptureStarted(param);
        break;
      case "onScreenCapturePaused":
        _handleOnScreenCapturePaused(param);
        break;
      case "onScreenCaptureResumed":
        _handleOnScreenCaptureResumed(param);
        break;
      case "onScreenCaptureStopped":
        _handleOnScreenCaptureStopped(param);
        break;
      case "onScreenCaptureCovered":
        _handleOnScreenCaptureCovered(param);
        break;
      case "onLocalRecordBegin":
        _handleOnLocalRecordBegin(param);
        break;
      case "onLocalRecording":
        _handleOnLocalRecording(param);
        break;
      case "onLocalRecordFragment":
        _handleOnLocalRecordFragment(param);
        break;
      case "onLocalRecordComplete":
        _handleOnLocalRecordComplete(param);
        break;
      default:
        break;
    }
  }

  _handleOnError(Map<String, dynamic> param) {
    int errCode = param['errCode'];
    String errMsg = param['errMsg'];

    for (TRTCCloudListener item in _listeners) {
      item.onError?.call(errCode, errMsg);
    }
  }

  _handleOnWarning(Map<String, dynamic> param) {
    int warnCode = param['warningCode'];
    String warnMsg = param['warningMsg'];

    for (TRTCCloudListener item in _listeners) {
      item.onWarning?.call(warnCode, warnMsg);
    }
  }

  _handleOnEnterRoom(Map<String, dynamic> param) {
    int result = param['result'];

    for (TRTCCloudListener item in _listeners) {
      item.onEnterRoom?.call(result);
    }
  }

  _handleOnExitRoom(Map<String, dynamic> param) {
    int reason = param['reason'];

    for (TRTCCloudListener item in _listeners) {
      item.onExitRoom?.call(reason);
    }
  }

  _handleOnSwitchRoom(Map<String, dynamic> param) {
    int errCode = param['errCode'];
    String errMsg = param['errMsg'];

    for (TRTCCloudListener item in _listeners) {
      item.onSwitchRoom?.call(errCode, errMsg);
    }
  }

  _handleOnSwitchRole(Map<String, dynamic> param) {
    int errCode = param['errCode'];
    String errMsg = param['errMsg'];

    for (TRTCCloudListener item in _listeners) {
      item.onSwitchRole?.call(errCode, errMsg);
    }
  }

  _handleOnConnectOtherRoom(Map<String, dynamic> param) {
    String userId = param['userId'];
    int errCode = param['errCode'];
    String errMsg = param['errMsg'];

    for (TRTCCloudListener item in _listeners) {
      item.onConnectOtherRoom?.call(userId, errCode, errMsg);
    }
  }

  _handleOnDisconnectOtherRoom(Map<String, dynamic> param) {
    int errCode = param['errCode'];
    String errMsg = param['errMsg'];

    for (TRTCCloudListener item in _listeners) {
      item.onDisconnectOtherRoom?.call(errCode, errMsg);
    }
  }

  _handleOnUserVideoAvailable(Map<String, dynamic> param) {
    String userId = param['userId'];
    bool available = param['available'];

    for (TRTCCloudListener item in _listeners) {
      item.onUserVideoAvailable?.call(userId, available);
    }
  }

  _handleOnUserSubStreamAvailable(Map<String, dynamic> param) {
    String userId = param['userId'];
    bool available = param['available'];

    for (TRTCCloudListener item in _listeners) {
      item.onUserSubStreamAvailable?.call(userId, available);
    }
  }

  _handleOnUserAudioAvailable(Map<String, dynamic> param) {
    String userId = param['userId'];
    bool available = param['available'];

    for (TRTCCloudListener item in _listeners) {
      item.onUserAudioAvailable?.call(userId, available);
    }
  }

  _handleOnRemoteUserEnterRoom(Map<String, dynamic> param) {
    String userId = param['userId'];

    for (TRTCCloudListener item in _listeners) {
      item.onRemoteUserEnterRoom?.call(userId);
    }
  }

  _handleOnRemoteUserLeaveRoom(Map<String, dynamic> param) {
    String userId = param['userId'];
    int reason = param['reason'];

    for (TRTCCloudListener item in _listeners) {
      item.onRemoteUserLeaveRoom?.call(userId, reason);
    }
  }

  _handleOnFirstVideoFrame(Map<String, dynamic> param) {
    String userId = param['userId'];
    int streamType = param['streamType'];
    int width = param['width'];
    int height = param['height'];

    for (TRTCCloudListener item in _listeners) {
      item.onFirstVideoFrame?.call(userId, TRTCVideoStreamTypeExt.fromValue(streamType), width, height);
    }
  }

  _handleOnFirstAudioFrame(Map<String, dynamic> param) {
    String userId = param['userId'];

    for (TRTCCloudListener item in _listeners) {
      item.onFirstAudioFrame?.call(userId);
    }
  }

  _handleOnSendFirstLocalVideoFrame(Map<String, dynamic> param) {
    int streamType = param['streamType'];

    for (TRTCCloudListener item in _listeners) {
      item.onSendFirstLocalVideoFrame?.call(TRTCVideoStreamTypeExt.fromValue(streamType));
    }
  }

  _handleOnSendFirstLocalAudioFrame(Map<String, dynamic> param) {
    for (TRTCCloudListener item in _listeners) {
      item.onSendFirstLocalAudioFrame?.call();
    }
  }

  _handleOnRemoteVideoStatusUpdated(Map<String, dynamic> param) {
    String userId = param['userId'];
    int streamType = param['streamType'];
    int status = param['statusType'];
    int changeReason = param['changeReason'];

    for (TRTCCloudListener item in _listeners) {
      item.onRemoteVideoStatusUpdated?.call(userId, TRTCVideoStreamTypeExt.fromValue(streamType), TRTCAVStatusTypeExt.fromValue(status), TRTCAVStatusChangeReasonExt.fromValue(changeReason));
    }
  }

  _handleOnRemoteAudioStatusUpdated(Map<String, dynamic> param) {
    String userId = param['userId'];
    int status = param['statusType'];
    int changeReason = param['changeReason'];

    for (TRTCCloudListener item in _listeners) {
      item.onRemoteAudioStatusUpdated?.call(userId, TRTCAVStatusTypeExt.fromValue(status), TRTCAVStatusChangeReasonExt.fromValue(changeReason));
    }
  }

  _handleOnUserVideoSizeChanged(Map<String, dynamic> param) {
    String userId = param['userId'];
    int streamType = param['streamType'];
    int newWidth = param['newWidth'];
    int newHeight = param['newHeight'];

    for (TRTCCloudListener item in _listeners) {
      item.onUserVideoSizeChanged?.call(userId, TRTCVideoStreamTypeExt.fromValue(streamType), newWidth, newHeight);
    }
  }

  _handleOnSpeedTestResult(Map<String, dynamic> param) {
    TRTCSpeedTestResult result = TRTCSpeedTestResult.fromJson(param);

    for (TRTCCloudListener item in _listeners) {
      item.onSpeedTestResult?.call(result);
    }
  }

  _handleOnConnectionLost(Map<String, dynamic> param) {
    for (TRTCCloudListener item in _listeners) {
      item.onConnectionLost?.call();
    }
  }

  _handleOnTryToReconnect(Map<String, dynamic> param) {
    for (TRTCCloudListener item in _listeners) {
      item.onTryToReconnect?.call();
    }
  }

  _handleOnConnectionRecovery(Map<String, dynamic> param) {
    for (TRTCCloudListener item in _listeners) {
      item.onConnectionRecovery?.call();
    }
  }

  _handleOnCameraDidReady(Map<String, dynamic> param) {
    for (TRTCCloudListener item in _listeners) {
      item.onCameraDidReady?.call();
    }
  }

  _handleOnMicDidReady(Map<String, dynamic> param) {
    for (TRTCCloudListener item in _listeners) {
      item.onMicDidReady?.call();
    }
  }

  _handleOnTestMicVolume(Map<String, dynamic> param) {
    int volume = param['volume'];

    for (TRTCCloudListener item in _listeners) {
      item.onTestMicVolume?.call(volume);
    }
  }

  _handleOnTestSpeakerVolume(Map<String, dynamic> param) {
    int volume = param['volume'];

    for (TRTCCloudListener item in _listeners) {
      item.onTestSpeakerVolume?.call(volume);
    }
  }

  _handleOnRecvCustomCmdMsg(Map<String, dynamic> param) {
    String userId = param['userId'];
    int cmdId = param['cmdId'];
    int seq = param['seq'];
    String message = param['message'];

    for (TRTCCloudListener item in _listeners) {
      item.onRecvCustomCmdMsg?.call(userId, cmdId, seq, message);
    }
  }

  _handleOnMissCustomCmdMsg(Map<String, dynamic> param) {
    String msg = param['msg'];
    int cmdId = param['cmdId'];
    int errCode = param['errCode'];
    int missed = param['missed'];

    for (TRTCCloudListener item in _listeners) {
      item.onMissCustomCmdMsg?.call(msg, cmdId, errCode, missed);
    }
  }

  _handleOnRecvSEIMsg(Map<String, dynamic> param) {
    String userId = param['userId'];
    String message = param['message'];

    for (TRTCCloudListener item in _listeners) {
      item.onRecvSEIMsg?.call(userId, message);
    }
  }

  _handleOnStartPublishMediaStream(Map<String, dynamic> param) {
    String taskId = param['taskId'];
    int code = param['code'];
    String message = param['message'];
    String extraInfo = param['extraInfo'];

    for (TRTCCloudListener item in _listeners) {
      item.onStartPublishMediaStream?.call(taskId, code, message, extraInfo);
    }
  }

  _handleOnUpdatePublishMediaStream(Map<String, dynamic> param) {
    String taskId = param['taskId'];
    int code = param['code'];
    String message = param['message'];
    String extraInfo = param['extraInfo'];

    for (TRTCCloudListener item in _listeners) {
      item.onUpdatePublishMediaStream?.call(taskId, code, message, extraInfo);
    }
  }

  _handleOnStopPublishMediaStream(Map<String, dynamic> param) {
    String taskId = param['taskId'];
    int code = param['code'];
    String message = param['message'];
    String extraInfo = param['extraInfo'];

    for (TRTCCloudListener item in _listeners) {
      item.onStopPublishMediaStream?.call(taskId, code, message, extraInfo);
    }
  }

  _handleOnCdnStreamStateChanged(Map<String, dynamic> param) {
    String cdnUrl = param['cdnUrl'];
    int status = param['status'];
    int code = param['code'];
    String message = param['message'];
    String extraInfo = param['extraInfo'];
    
    for (TRTCCloudListener item in _listeners) {
      item.onCdnStreamStateChanged?.call(cdnUrl, status, code, message, extraInfo);
    }
  }

  _handleOnScreenCaptureStarted(Map<String, dynamic> param) {
    for (TRTCCloudListener item in _listeners) {
      item.onScreenCaptureStarted?.call();
    }
  }

  _handleOnScreenCapturePaused(Map<String, dynamic> param) {
    int reason = param['reason'];
    
    for (TRTCCloudListener item in _listeners) {
      item.onScreenCapturePaused?.call(reason);
    }
  }

  _handleOnScreenCaptureResumed(Map<String, dynamic> param) {
    int reason = param['reason'];
    
    for (TRTCCloudListener item in _listeners) {
      item.onScreenCaptureResumed?.call(reason);
    }
  }

  _handleOnScreenCaptureStopped(Map<String, dynamic> param) {
    int reason = param['reason'];
    
    for (TRTCCloudListener item in _listeners) {
      item.onScreenCaptureStopped?.call(reason);
    }
  }

  _handleOnScreenCaptureCovered(Map<String, dynamic> param) {
    for (TRTCCloudListener item in _listeners) {
      item.onScreenCaptureCovered?.call();
    }
  }

  _handleOnLocalRecordBegin(Map<String, dynamic> param) {
    int errCode = param['errCode'];
    String storagePath = param['storagePath'];
    
    for (TRTCCloudListener item in _listeners) {
      item.onLocalRecordBegin?.call(errCode, storagePath);
    }
  }

  _handleOnLocalRecording(Map<String, dynamic> param) {
    int duration = param['duration'];
    String storagePath = param['storagePath'];
    
    for (TRTCCloudListener item in _listeners) {
      item.onLocalRecording?.call(duration, storagePath);
    }
  }

  _handleOnLocalRecordFragment(Map<String, dynamic> param) {
    String storagePath = param['storagePath'];

    for (TRTCCloudListener item in _listeners) {
      item.onLocalRecordFragment?.call(storagePath);
    }
  }

  _handleOnLocalRecordComplete(Map<String, dynamic> param) {
    int errCode = param['errCode'];
    String storagePath = param['storagePath'];
    
    for (TRTCCloudListener item in _listeners) {
      item.onLocalRecordComplete?.call(errCode, storagePath);
    }
  }

  _handleOnUserVoiceVolume(Map<String, dynamic> param) {
    List<TRTCVolumeInfo> volumeInfo = [];
    List userVolumes = param['userVolumes'];
    for (var i = 0; i < userVolumes.length; i++) {
      volumeInfo.add(TRTCVolumeInfo.fromJson(userVolumes[i]));
    }

    int totalVolume = param['totalVolume'];

    for (TRTCCloudListener item in _listeners) {
      item.onUserVoiceVolume?.call(volumeInfo, totalVolume);
    }
  }

  _handleOnAudioDeviceCaptureVolumeChanged(Map<String, dynamic> param) {
    int volume = param['volume'];
    bool muted = param['muted'];

    for (TRTCCloudListener item in _listeners) {
      item.onAudioDeviceCaptureVolumeChanged?.call(volume, muted);
    }
  }

  _handleOnAudioDevicePlayoutVolumeChanged(Map<String, dynamic> param) {
    int volume = param['volume'];
    bool muted = param['muted'];

    for (TRTCCloudListener item in _listeners) {
      item.onAudioDevicePlayoutVolumeChanged?.call(volume, muted);
    }
  }

  _handleOnSystemAudioLoopbackError(Map<String, dynamic> param) {
    int errCode = param['errCode'];

    for (TRTCCloudListener item in _listeners) {
      item.onSystemAudioLoopbackError?.call(errCode);
    }
  }

  _handleOnNetworkQuality(Map<String, dynamic> param) {
    TRTCQualityInfo localInfo = TRTCQualityInfo.fromJson(param['localQuality']);

    List<TRTCQualityInfo> remoteInfoList = [];
    List remoteQualityList = param['remoteQuality'];
    for (var i = 0; i < remoteQualityList.length; i++) {
      remoteInfoList.add(TRTCQualityInfo.fromJson(remoteQualityList[i]));
    }

    for (TRTCCloudListener item in _listeners) {
      item.onNetworkQuality?.call(localInfo, remoteInfoList);
    }
  }

  _handleOnStatistics(Map<String, dynamic> param) {
    TRTCStatistics statistics = TRTCStatistics.fromJson(param);

    for (TRTCCloudListener item in _listeners) {
      item.onStatistics?.call(statistics);
    }
  }
}

class TRTCAudioFrameCallbackParse extends ListenerParse<TRTCAudioFrameCallback> {
  @override
  void handleListener(String type, Map<String, dynamic> param) {
    switch (type) {
      case 'onCapturedAudioFrame':
        _handleOnCapturedAudioFrame(param);
        break;
      case 'onLocalProcessedAudioFrame':
        _handleOnLocalProcessedAudioFrame(param);
        break;
      case 'onPlayAudioFrame':
        _handleOnPlayAudioFrame(param);
        break;
      case 'onMixedPlayAudioFrame':
        _handleOnMixedPlayAudioFrame(param);
        break;
      case 'onMixedAllAudioFrame':
        _handleOnMixedAllAudioFrame(param);
        break;
      default:
        break;
    }
  }

  _handleOnCapturedAudioFrame(Map<String, dynamic> param) {
    TRTCAudioFrame frame = TRTCAudioFrame.fromJson(param['frame']);

    for (TRTCAudioFrameCallback item in _listeners) {
      item.onCapturedAudioFrame(frame);
    }
  }

  _handleOnLocalProcessedAudioFrame(Map<String, dynamic> param) {
    TRTCAudioFrame frame = TRTCAudioFrame.fromJson(param['frame']);

    for (TRTCAudioFrameCallback item in _listeners) {
      item.onLocalProcessedAudioFrame(frame);
    }
  }

  _handleOnPlayAudioFrame(Map<String, dynamic> param) {
    TRTCAudioFrame frame = TRTCAudioFrame.fromJson(param['frame']);
    String userId = param['userId'];

    for (TRTCAudioFrameCallback item in _listeners) {
      item.onPlayAudioFrame(frame, userId);
    }
  }

  _handleOnMixedPlayAudioFrame(Map<String, dynamic> param) {
    TRTCAudioFrame frame = TRTCAudioFrame.fromJson(param['frame']);

    for (TRTCAudioFrameCallback item in _listeners) {
      item.onMixedPlayAudioFrame(frame);
    }
  }

  _handleOnMixedAllAudioFrame(Map<String, dynamic> param) {
    TRTCAudioFrame frame = TRTCAudioFrame.fromJson(param['frame']);

    for (TRTCAudioFrameCallback item in _listeners) {
      item.onMixedAllAudioFrame(frame);
    }
  }
}

class TRTCLogCallbackParse extends ListenerParse<TRTCLogCallback>{
  @override
  void handleListener(String type, Map<String, dynamic> param) {
    switch (type) {
      case 'onLog':
        _handleOnLog(param);
        break;
      default:
        break;
    }
  }
  
  _handleOnLog(Map<String, dynamic> param) {
    String log = param['log'];
    int level = param['log_level'];
    String module = param['module'];
    
    for (TRTCLogCallback item in _listeners) {
      item.onLog(log, TRTCLogLevelExt.fromValue(level), module);
    }
  }
  
}

class TXMusicPlayObserverParse  {
  final Map<int, TXMusicPlayObserver> listeners = {};

  void handleListener(String type, Map<String, dynamic> param) {
    switch (type) {
      case 'onStart':
        _handleOnStart(param);
        break;
      case 'onPlayProgress':
        _handleOnPlayProgress(param);
        break;
      case 'onComplete':
        _handleOnComplete(param);
        break;
      default:
        break;
    }
  }

  _handleOnStart(Map<String, dynamic> param) {
    int musicId = param['musicId'];
    int errCode = param['errCode'];

    TXMusicPlayObserver? observer = listeners[musicId];
    observer?.onStart(musicId, errCode);
  }

  _handleOnPlayProgress(Map<String, dynamic> param) {
    int musicId = param['musicId'];
    int curPtsMs = param['curPtsMs'];
    int durationMs = param['durationMs'];

    TXMusicPlayObserver? observer = listeners[musicId];
    observer?.onPlayProgress(musicId, curPtsMs, durationMs);
  }

  _handleOnComplete(Map<String, dynamic> param) {
    int musicId = param['musicId'];
    int errCode = param['errCode'];

    TXMusicPlayObserver? observer = listeners[musicId];
    observer?.onComplete(musicId, errCode);
  }
}

class TXMusicPreloadObserverParse extends ListenerParse<TXMusicPreloadObserver>{
  @override
  void handleListener(String type, Map<String, dynamic> param) {
    switch (type) {
      case 'onLoadProgress':
        _handleOnLoadProgress(param);
        break;
      case 'onLoadError':
        _handleOnLoadError(param);
        break;
      default:
        break;
    }
  }

  _handleOnLoadProgress(Map<String, dynamic> param) {
    int musicId = param['musicId'];
    int progress = param['progress'];

    for (TXMusicPreloadObserver item in _listeners) {
      item.onLoadProgress(musicId, progress);
    }
  }

  _handleOnLoadError(Map<String, dynamic> param) {
    int musicId = param['musicId'];
    int errCode = param['errCode'];

    for (TXMusicPreloadObserver item in _listeners) {
      item.onLoadError(musicId, errCode);
    }
  }
}

class TXDeviceObserverParse extends ListenerParse<TXDeviceObserver>{
  @override
  void handleListener(String type, Map<String, dynamic> param) {
    switch (type) {
      case 'onDeviceChanged':
        _handleOnDeviceChanged(param);
        break;
      default:
        break;
    }
  }

  _handleOnDeviceChanged(Map<String, dynamic> param) {
    String deviceId = param['deviceId'];
    int type = param['type'];
    int state = param['state'];

    for (TXDeviceObserver item in _listeners) {
      item.onDeviceChanged(deviceId, TXMediaDeviceTypeExt.fromValue(type), TXMediaDeviceStateExt.fromValue(state));
    }
  }
}